//
//  SYDefaults.swift
//  Entrance
//
//  Created by chunhuiLai on 2018/1/12.
//  Copyright © 2018年 chunhuiLai. All rights reserved.
//
import Foundation

public struct Listener<T>: Hashable {
    
    let name: String
    
    public typealias Action = (T) -> Void
    let action: Action
    
    public var hashValue: Int {
        return name.hashValue
    }
}

public func ==<T>(lhs: Listener<T>, rhs: Listener<T>) -> Bool {
    return lhs.name == rhs.name
}

final public class Listenable<T> {
    
    public var value: T {
        didSet {
            setterAction(value)
            
            for listener in listenerSet {
                listener.action(value)
            }
        }
    }
    
    public typealias SetterAction = (T) -> Void
    var setterAction: SetterAction
    
    var listenerSet = Set<Listener<T>>()
    
    public func bindListener(name: String, action: @escaping Listener<T>.Action) {
        let listener = Listener(name: name, action: action)
        
        listenerSet.insert(listener)
    }
    
    public func bindAndFireListener(name: String, action: @escaping Listener<T>.Action) {
        bindListener(name: name, action: action)
        
        action(value)
    }
    
    public func removeListenerWithName(name: String) {
        for listener in listenerSet {
            if listener.name == name {
                listenerSet.remove(listener)
                break
            }
        }
    }
    
    public func removeAllListeners() {
        listenerSet.removeAll(keepingCapacity: false)
    }
    
    public init(_ v: T, setterAction action: @escaping SetterAction) {
        value = v
        setterAction = action
    }
}


final public class SYDefaults: NSObject {
    
    static let shared = UserDefaults.standard
    
    class func clean(forKey key: String) {
        
    }
    
//    static var experienceMoney: Listenable<String?> = {
//        let experienceMoney = defaults.string(forKey: treasureKey(.experienceMoney))
//
//        return Listenable<String?>(experienceMoney) { experienceMoney in
//            defaults.set(experienceMoney, forKey: treasureKey(.experienceMoney))
//        }
//    }()
//
    public class func cleanAll() {
        
        do {
//            moneyPacket.removeAllListeners()
//            investmentPacket.removeAllListeners()
//            withdrawCoupon.removeAllListeners()
//            raiseInterestCoupon.removeAllListeners()
//            experienceMoney.removeAllListeners()
//            signCard.removeAllListeners()
//            gift.removeAllListeners()
        }
        
        do {
//            withdrawCoupon.value = nil
//            moneyPacket.value = nil
//            investmentPacket.value = nil
//            raiseInterestCoupon.value = nil
//            signCard.value = nil
//            experienceMoney.value = nil
//            gift.value = nil
        }
    }
}

private extension Date {
    var isInPast: Bool {
        let now = Date()
        return self.compare(now) == ComparisonResult.orderedAscending
    }
}

struct SYToken {
    enum DefaultsKeys: String {
        case tokenKey
        case tokenExpiryKey
    }
    
    let defaults: UserDefaults
    
    init() {
        defaults = UserDefaults.standard
    }
    
    var token: String? {
        get {
            let key = defaults.string(forKey: DefaultsKeys.tokenKey.rawValue)
            return key
        }
        set(newToken) {
            defaults.set(newToken, forKey: DefaultsKeys.tokenKey.rawValue)
        }
    }
    
    var expiry: Date? {
        get {
            return defaults.object(forKey: DefaultsKeys.tokenExpiryKey.rawValue) as? Date
        }
        set(newExpiry) {
            defaults.set(newExpiry, forKey: DefaultsKeys.tokenExpiryKey.rawValue)
        }
    }
    
    var expired: Bool {
        if let expiry = expiry {
            return expiry.isInPast
        }
        return true
    }
    
    var isValid: Bool {
        if let token = token {
            return !token.isEmpty && !expired
        }
        
        return false
    }
}


